﻿using SymulatorEthernetWPF.Shared;
using SymulatorEthernetWPF.SimObjects.Devices;
using SymulatorEthernetWPF.SimObjects.Layers.DataLink;
using SymulatorEthernetWPF.SimObjects.Layers.Physical;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Windows.Media;

namespace SymulatorEthernetWPF.SimObjects.Wires
{
    [Serializable]
    public class WireEnd : ISerializable
    {
        public Wire wire;
        public NetworkInterface networkInterface;
        public Guid GUID;

        public ObservableCollection<Signal> signals = new ObservableCollection<Signal>();

        public WireEnd(Wire wire, NetworkInterface networkInterface)
        {
            this.wire = wire;
            this.networkInterface = networkInterface;
            signals.CollectionChanged += signals_CollectionChanged;
        }

        void signals_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (signals.Count != 0)
                networkInterface.isSending = true;
            else
                networkInterface.isSending = false;
        }

       

        public WireEnd getOtherEnd()
        {
            if (wire.wireEndA != this) return wire.wireEndA;
            else return wire.wireEndB;
        }
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("wire", wire);
            info.AddValue("NetworkInterface", networkInterface);
            info.AddValue("GUID", GUID);
        }
        public WireEnd(SerializationInfo info, StreamingContext context)
        {
            GUID = (Guid)info.GetValue("GUID", typeof(Guid));
            wire = (Wire)info.GetValue("wire", typeof(Wire));
            networkInterface = (NetworkInterface)info.GetValue("NetworkInterface", typeof(NetworkInterface));
            signals.CollectionChanged += signals_CollectionChanged;
        }

        public void sendSignal(Ethernet frame)
        {
            if (getOtherEnd() != null)
            {
                Signal signal = new Signal(this, frame);
                StaticVars.MainWindow.customCanvas.Children.Add(signal);
                signals.Add(signal);
                networkInterface.Owner.logList.Add("[" + Simulation.tickCount + "](" + networkInterface.Name + ") Wysyłanie ramki");
                DelayTimer normalSignalWireDelay = new DelayTimer(1000.0 * (1.0 / (double)networkInterface.wireEnd.getConnectionType()), null, signal);
                normalSignalWireDelay.Tick += normalSignalWireDelay_Tick;
                normalSignalWireDelay.Start();                
            }
        }

        void normalSignalWireDelay_Tick(object sender, EventArgs e)
        {
            ((DelayTimer)sender).Stop();
            getOtherEnd().networkInterface.receiveSignalStart(((DelayTimer)sender).signal);
        }

        public void sendJam()
        {
            if (getOtherEnd() != null)
            {
                Signal signal = new Signal(this, null, true);
                StaticVars.MainWindow.customCanvas.Children.Add(signal);
                signals.Add(signal);
                networkInterface.Owner.logList.Add("[" + Simulation.tickCount + "](" + networkInterface.Name + ") Wysyłanie zagłuszenia");
                DelayTimer jamSignalWireDelay = new DelayTimer(100.0 * (1.0 / (double)networkInterface.wireEnd.getConnectionType()), null, signal);
                jamSignalWireDelay.Tick += jamSignalWireDelay_Tick;
                jamSignalWireDelay.Start();
                
            }
            
        }

        void jamSignalWireDelay_Tick(object sender, EventArgs e)
        {
            ((DelayTimer)sender).Stop();
            getOtherEnd().networkInterface.receiveSignalStart(((DelayTimer)sender).signal);
        }

        public void signalReceived(Signal signal)
        {
            wire.Stroke = Brushes.Black;
            signals.Remove(signal);
            networkInterface.signalReceived(signal);

        }

        public void stopSignals()
        {
            if (signals.Count > 0)
            {
                for (int i = signals.Count - 1; i >= 0; i--)
                {
                    signals[i].stop();
                }
                signals = new ObservableCollection<Signal>();
                signals.CollectionChanged += signals_CollectionChanged;
                
            }
        }

        public ConnectionType getConnectionType()
        {
            return wire.connectionType;
        }
    }
}
